/**
 * 工程名称:oms
 * 文件名称:StockCaculator.java
 * 所属包:cn.rkylin.oms.system.stockpush.util
 * 创建时间:2017年9月11日上午11:15:41
 * Copyright (c) 2017 瑞金麟(大连)信息技术有限公司 All Rights Reserved.
 * 创建人:zhanghao
 */

package cn.rkylin.oms.system.stockpush.util;

import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import cn.rkylin.oms.system.stockpush.controller.StockPushController;


/**
 * 类名:StockCaculator <br/>
 * 作用: 库存计算类. <br/>
 * 创建原因: 用于仓库库存公式的解析和计算. <br/>
 * 创建时间: 2017年9月11日 上午11:15:41 <br/>
 * 
 * @author zhanghao
 * @version v1.0
 * @since JDK 1.6
 * @see
 */
public abstract class AbstractStockCaculator implements IStockCaculator  {
    /**
     * availableParam:合法参数.
     * 
     * @since JDK 1.6
     */
    final String[] availableParam = { "库存数", "在途数", "已分派", "未分派", "未付款", "预留数", "冻结数" };
    /**
     * availableOperation:合法操作符.
     * 
     * @since JDK 1.6
     */
    final String[] availableOperation = { "+", "-", "*", "/", "(", ")" };
    
    /**
     * pattern:用于校验变量形式的正则表达式，检出“{{变量名}}”.
     * @since JDK 1.6
     */
    private Pattern pattern = Pattern.compile("\\{\\{[^}]*\\}\\}");;
    protected static final Log logger = LogFactory.getLog(StockPushController.class);

    /**
     * caculateResult:根据公式和参数计算结果. <br/>
     * 公式需要是正确的表达式，参数需要是0或者正整数.<br/>
     * 先判断公式中的参数是否合法，然后判断公式的计算符号是否合法，然后执行计算.<br/>
     * 当公式和参数都正确时，返回计算结果的字符串形式；当表达式或者参数不对时，给出错误提示信息：{errCode:errorCode,errMsg:errMsg}.<br/>
     * 只用于根据公式进行库存计算.<br/>
     *
     * @author zhanghao
     * @param fmla
     * @param paramMap
     * @return
     * @since JDK 1.6
     */
    @Override
    public String caculateResult(String fmla, Map paramMap) {
        String returnResult = "";
        String caculateResult = "0";
        // 校验公式中的参数项是否都合法
        if (!validateParam(fmla, paramMap)||!validateOperation(fmla)) {
            logger.error("已将本次计算结果设置为：0");
            caculateResult = "";
        }else {
            // 执行计算
            caculateResult = caculate(fmla, paramMap);
        }
        return caculateResult;
    }
    
    public abstract String caculate(String fmla,Map paramMap);

    /**
     * validateParam:校验公式中的参数项是否合法. <br/>
     *
     * @author zhanghao
     * @param fmla
     * @param param
     * @return
     * @since JDK 1.6
     */
    public boolean validateParam(String fmla, Map param) {
        boolean returnBoolean = true;
        Matcher matcher = pattern.matcher(fmla);
        List<String> paramList = Arrays.asList(availableParam);
        while(matcher.find()) {
            String matchStr = matcher.group();
            if(!paramList.contains(matchStr.substring(2, matchStr.length()-2))) {
                logger.error("公式"+fmla+"中存在不合法的参数");
                returnBoolean = false;
                break;
            }
        }
        return returnBoolean;
    }

    /**
     * validateOperation:校验公式中的操作符是否合法. <br/>
     *
     * @author zhanghao
     * @param fmla
     * @return
     * @since JDK 1.6
     */
    public boolean validateOperation(String fmla) {
        boolean returnBoolean = true;
        String testString = pattern.matcher(fmla).replaceAll("");
        testString = StringUtils.replace(testString, " ", "");
        
        List<String> operationList = Arrays.asList(availableOperation);
        String tempString = "";
        for(int i=0,j=testString.length();i<j;i++) {
            tempString =  String.valueOf(testString.charAt(i));
            if(!operationList.contains(tempString)) {
                logger.error("公式"+fmla+"中存在不合法的计算符号");
                returnBoolean = false;
            }
        }
        return returnBoolean;
    }
    
    protected String generateSuccessMessage(String result) {
        return String.format("{returnCode:\"success\",returnMsg:\"%s\"}", result);
    }
    protected String generateErrorMessage(String code,String msg) {
        return String.format("{returnCode:\"%s\",Msg:\"%s\"}", code,msg);
    }
}
